package com.foreverwin.mes.production.service.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.foreverwin.mes.common.constants.HandleBOConstants;
import com.foreverwin.mes.core.exception.BusinessException;
import com.foreverwin.mes.core.utils.StringUtils;
import com.foreverwin.mes.core.utils.TimeUtils;
import com.foreverwin.mes.meapi.enums.CustomFieldsConstant;
import com.foreverwin.mes.meapi.model.*;
import com.foreverwin.mes.meapi.model.BomComponent;
import com.foreverwin.mes.meapi.service.*;
import com.foreverwin.mes.production.dto.*;
import com.foreverwin.mes.production.mapper.SfcExMapper;
import com.foreverwin.mes.production.model.ResourceInventory;
import com.foreverwin.mes.production.model.SfcExtend;
import com.foreverwin.mes.production.service.ResourceInventoryService;
import com.foreverwin.mes.production.service.SfcExService;
import com.sap.me.common.NameValueObject;
import com.sap.me.demand.SfcIdentifier;
import com.sap.me.demand.*;
import com.sap.me.extension.Services;
import com.sap.me.frame.transitionutils.Exceptions;
import com.sap.me.numbering.GenerateNextNumberRequest;
import com.sap.me.numbering.GenerateNextNumberResponse;
import com.sap.me.numbering.NextNumberTypeEnum;
import com.sap.me.numbering.NumberingServiceInterface;
import com.sap.me.production.*;
import org.apache.cxf.Bus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @program: mesext
 * @description: 生产过站服务实现
 * @author: syngna
 * @create: 2020-02-17 11:20
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class SfcExServiceImpl extends ServiceImpl<SfcExMapper, SfcExtend> implements SfcExService {

    @Autowired
    public SfcService sfcService;

    @Autowired
    public SfcExMapper sfcExMapper;

    @Autowired
    public CustomFieldsService customFieldsService;

    @Autowired
    public OperationService operationService;

    @Autowired
    public ShopOrderService shopOrderService;

    @Autowired
    public WorkCenterShiftServiceImpl workCenterShiftService;

    @Autowired
    public ItemService itemService;

    @Autowired
    public BomService bomService;

    @Autowired
    public ResourceInventoryService resourceInventoryService;

    @Autowired
    public InventoryService inventoryService;

    @Autowired
    public WorkCenterService workCenterService;

    /**
     * 下达并开始生产批，如果生产批已存在则不下达直接开始
     *
     * @param releaseAndStartSfcDto
     */
    @Override
    public ReleaseAndStartSfcResponse releaseAndStartSfc(ReleaseAndStartSfcDto releaseAndStartSfcDto) {
        ReleaseAndStartSfcResponse releaseAndStartSfcResponse = new ReleaseAndStartSfcResponse();
        String site = releaseAndStartSfcDto.getSite();

        String operationBo = releaseAndStartSfcDto.getOperationBo();
        String operation = StringUtils.trimHandle(operationBo);
        if (operationBo.endsWith("#")) {
            List<Operation> operationList = operationService.selectList(new EntityWrapper<Operation>()
                    .eq(Operation.SITE, site)
                    .eq(Operation.OPERATION, operation)
                    .eq(Operation.CURRENT_REVISION, "true"));
            if (operationList == null || operationList.size() == 0) {
                throw BusinessException.build("工序【" + operation + "】当前版本不存在");
            }
            operationBo = operationList.get(0).getHandle();
        }
        List<CustomFields> customFieldsList = customFieldsService.listByHandle(operationBo);
        // 上料校验
        boolean slotCheck = false;
        // 成品入库
        boolean finishOperation = false;
        for (CustomFields customFields : customFieldsList) {
            if (CustomFieldsConstant.KW_OPERATION_SLOT_CHECK.equalsIgnoreCase(customFields.getAttribute()) && "Y".equalsIgnoreCase(customFields.getValue())) {
                slotCheck = true;
            }
            if (CustomFieldsConstant.KW_OPERATION_FINISH_OPERATION.equalsIgnoreCase(customFields.getAttribute()) && "Y".equalsIgnoreCase(customFields.getValue())) {
                finishOperation = true;
            }
        }
        if (slotCheck) {
            // 上料校验
            checkResourceInventory(site, StringUtils.trimHandle(releaseAndStartSfcDto.getResourceBo()), releaseAndStartSfcDto.getShopOrderBo());
        }
        Sfc sfc = sfcService.selectById(releaseAndStartSfcDto.getSfcBo());
        ShopOrderServiceInterface shopOrderServiceInterface = Services.getService("com.sap.me.demand", "ShopOrderService", site);
        try {
            // 工单下达
            if (sfc == null) {
                String sfcNumber = StringUtils.trimHandle(releaseAndStartSfcDto.getSfcBo());
                if (finishOperation) {
                    // 产生成品入库生产批号
                    sfcNumber = generateFinishOperationNumber(site, releaseAndStartSfcDto);
                }
                ReleaseShopOrderRequest releaseShopOrderRequest = new ReleaseShopOrderRequest();
                releaseShopOrderRequest.setShopOrderRef(releaseAndStartSfcDto.getShopOrderBo());
                if (releaseAndStartSfcDto.getReleaseAppointSfc() != null && releaseAndStartSfcDto.getReleaseAppointSfc()) {
                    SfcIdentifier sfcIdentifier = new SfcIdentifier();
                    sfcIdentifier.setId(sfcNumber);
                    releaseShopOrderRequest.setNewSfcList(Arrays.asList(sfcIdentifier));
                }
                releaseShopOrderRequest.setQuantityToRelease(releaseAndStartSfcDto.getQuantityToRelease());
                ReleaseShopOrderResponse releaseShopOrderResponse = shopOrderServiceInterface.releaseShopOrder(releaseShopOrderRequest);
                List<ReleasedSfc> releasedSfcList = releaseShopOrderResponse.getReleasedSfcList();
                if (releasedSfcList != null && releasedSfcList.size() > 0) {
                    releaseAndStartSfcResponse.setReleasedSfcRefs(new ArrayList<>());
                    // 生产批开始
                    for (ReleasedSfc releasedSfc : releasedSfcList) {
                        sfcStart(site, releaseAndStartSfcDto.getResourceBo(), releaseAndStartSfcDto.getOperationBo(), releasedSfc.getSfcRef());
                        releaseAndStartSfcResponse.getReleasedSfcRefs().add(releasedSfc.getSfcRef());
                    }
                }
            } else {
                // 生产批开始
                sfcStart(site, releaseAndStartSfcDto.getResourceBo(), releaseAndStartSfcDto.getOperationBo(), releaseAndStartSfcDto.getSfcBo());
            }
        } catch (com.sap.me.frame.domain.BusinessException e) {
            throw BusinessException.build(Exceptions.convert(e).toString());
        }
        return releaseAndStartSfcResponse;
    }

    private void checkResourceInventory(String site, String resource, String shopOrderBo) {
        ShopOrder shopOrder = shopOrderService.selectById(shopOrderBo);
        String bomBo = shopOrder.getPlannedBomBo();
        if (StringUtils.isBlank(bomBo)) {
            String plannedItemBo = shopOrder.getPlannedItemBo();
            Item item = null;
            if (StringUtils.notBlank(plannedItemBo) && plannedItemBo.endsWith("#")) {
                item = itemService.selectItemByCode(site, StringUtils.trimHandle(plannedItemBo));
            } else {
                item = itemService.selectById(plannedItemBo);
            }
            if (item != null) {
                bomBo = item.getBomBo();
            }
        }
        if (StringUtils.notBlank(bomBo)) {
            Bom bom = bomService.getBomInfo(site, bomBo);
            if (bom != null && bom.getBomComponentList() != null && bom.getBomComponentList().size() > 0) {
                List<String> bomComponentList = bom.getBomComponentList().stream().map(BomComponent::getComponentGbo).collect(Collectors.toList());
                List<ResourceInventory> resourceInventorieList = resourceInventoryService.selectList(new EntityWrapper<ResourceInventory>()
                        .eq(ResourceInventory.SITE, site)
                        .eq(ResourceInventory.RESRCE, resource)
                        .in(ResourceInventory.ITEM_BO, bomComponentList)
                        .andNew().isNull(ResourceInventory.SHOP_ORDER).or().eq(ResourceInventory.SHOP_ORDER, "").or().eq(ResourceInventory.SHOP_ORDER, shopOrder.getShopOrder()));
                List<String> missItems = new ArrayList<>();
                if (resourceInventorieList != null && resourceInventorieList.size() > 0) {
                    for (String bomComponent : bomComponentList) {
                        boolean exists = false;
                        for (ResourceInventory resourceInventory : resourceInventorieList) {
                            if (bomComponent.equals(resourceInventory.getItemBo())) {
                                exists = true;
                            }
                        }
                        if (!exists) {
                            missItems.add(StringUtils.trimHandle(bomComponent) + "/" + StringUtils.trimRevision(bomComponent));
                        }
                    }
                } else {
                    for (String bomComponent : bomComponentList) {
                        missItems.add(StringUtils.trimHandle(bomComponent) + "/" + StringUtils.trimRevision(bomComponent));
                    }
                }
                if (missItems.size() > 0) {
                    throw BusinessException.build("工单【" + shopOrder.getShopOrder() + "】在设备【" + resource + "】上料缺失" + missItems);
                }
            }
        }
    }

    @Override
    public void sfcStart(String site, String resourceBo, String operationBo, String sfcBo) {
        SfcStartServiceInterface sfcStartServiceInterface = Services.getService("com.sap.me.production", "SfcStartService", site);
        StartSfcRequest startSfcRequest = new StartSfcRequest();
        startSfcRequest.setResourceRef(resourceBo);
        startSfcRequest.setOperationRef(operationBo);
        startSfcRequest.setSfcRef(sfcBo);
        try {
            sfcStartServiceInterface.startSfc(startSfcRequest);
        } catch (com.sap.me.frame.domain.BusinessException e) {
            throw BusinessException.build(Exceptions.convert(e).toString());
        }
    }

    @Override
    public void sfcComplete(String site, String user, String resourceBo, String operationBo, String sfcBo, BigDecimal qty, Boolean close) {
        // 当前工序工作中数量不够则下达并开始不够的部分数量，如果继续生产，需要超量下达， 不继续生产则关闭SFC和任务
        // 排队中和已完成数量+本次传入数量超过物料批次数量则不允许操作(me标准接口应该会自己校验)
        // 查询当前工序工作中中数量
        String resource = StringUtils.trimHandle(resourceBo);
        String operation = StringUtils.trimHandle(operationBo);
        String sfc = StringUtils.trimHandle(sfcBo);
        try {
            FindSfcByNameRequest findSfcByNameRequest = new FindSfcByNameRequest();
            findSfcByNameRequest.setSfc(sfc);
            SfcStateServiceInterface sfcStateServiceInterface = Services.getService("com.sap.me.production", "SfcStateService", site);
            SfcBasicData sfcBasicData = sfcStateServiceInterface.findSfcByName(findSfcByNameRequest);
            // Sfc sfcPo = sfcService.selectById(sfcBo);
            if (sfcBasicData == null || StringUtils.isBlank(sfcBasicData.getSfc())) {
                throw BusinessException.build("生产批【" + sfc + "】不存在");
            }
            String status = StringUtils.trimHandle(sfcBasicData.getStatusRef());
            if("405".equals(status)) {
                throw BusinessException.build("生产批【" + sfc + "】已完成");
            }
            List<SfcInWorkDto> sfcInWorkDtoList = this.listSfcInWork(site, resource, operation, sfc);
            /*if(sfcInWorkDtoList == null || sfcInWorkDtoList.size() == 0) {
                throw BusinessException.build("没有工作中的生产批【"  + sfc +"】");
            }*/
            BigDecimal inWorkQty = BigDecimal.ZERO;
            if (sfcInWorkDtoList != null && sfcInWorkDtoList.size() > 0) {
                inWorkQty = new BigDecimal(sfcInWorkDtoList.get(0).getQtyInWork());
            }
            // 工作中数量不足
            if (inWorkQty.compareTo(qty) <= 0) {
                BigDecimal needMoreQty = qty.subtract(inWorkQty);
                // 继续生产
                if (!close) {
                    // 多下达数量1
                    needMoreQty = needMoreQty.add(BigDecimal.ONE);
                }
                // 需要下达更多数量
                if (needMoreQty.compareTo(BigDecimal.ZERO) > 0) {
                    ShopOrderServiceInterface shopOrderServiceInterface = Services.getService("com.sap.me.demand", "ShopOrderService", site);
                    ReleaseShopOrderRequest releaseShopOrderRequest = new ReleaseShopOrderRequest();
                    releaseShopOrderRequest.setShopOrderRef(sfcBasicData.getShopOrderRef());
                    // 工单下达不能直接追加到当前SFC，使用松散工艺路线追加会导致多个SFC同时生产时只追加到最后一个SFC，所以拆分为先下达到临时SFC,然后MERGE
                    // 工单下达到临时SFC
                    String tempSfc = sfc + "_" + new Date().getTime();
                    SfcIdentifier sfcIdentifier = new SfcIdentifier();
                    sfcIdentifier.setId(StringUtils.trimHandle(tempSfc));
                    releaseShopOrderRequest.setNewSfcList(Arrays.asList(sfcIdentifier));
                    releaseShopOrderRequest.setQuantityToRelease(needMoreQty);
                    ReleaseShopOrderResponse releaseShopOrderResponse = shopOrderServiceInterface.releaseShopOrder(releaseShopOrderRequest);
                    List<ReleasedSfc> releasedSfcList = releaseShopOrderResponse.getReleasedSfcList();
                    // 由临时SFC merge到当前SFC
                    SfcMergeServiceInterface sfcMergeServiceInterface = Services.getService("com.sap.me.production", "SfcMergeService", site);
                    SfcMergeRequest sfcMergeRequest = new SfcMergeRequest();
                    sfcMergeRequest.setSfc(sfc);
                    sfcMergeRequest.setChildSfcList(Arrays.asList(tempSfc));
                    sfcMergeServiceInterface.merge(sfcMergeRequest);
                    // 当前SFC开始
                    sfcStart(site, resourceBo, operationBo, sfcBo);
                }
            }
            // 完成
            SfcCompleteServiceInterface sfcCompleteService = Services.getService("com.sap.me.production", "SfcCompleteService", site);
            CompleteSfcRequest completeSfcRequest = new CompleteSfcRequest();
            completeSfcRequest.setResourceRef(resourceBo);
            completeSfcRequest.setOperationRef(operationBo);
            completeSfcRequest.setSfcRef(sfcBo);
            completeSfcRequest.setQuantity(qty);
            sfcCompleteService.completeSfc(completeSfcRequest);
            Inventory inventory = inventoryService.selectById(StringUtils.genHandle(HandleBOConstants.INVENTORY_BO, site, sfc));
            if(inventory != null) {
                WorkCenter workCenter = workCenterService.getWorkCenterByWorkCenterOrResource(resourceBo);
                if(workCenter != null) {
                    Inventory updateParam = new Inventory();
                    updateParam.setHandle(inventory.getHandle());
                    updateParam.setWorkCenterLocBo(workCenter.getHandle());
                    inventoryService.updateById(updateParam);
                }
            }
            if (close) {
                // 关闭任务&关闭SFC
                List<SfcSoDispRelDto> taskList = sfcExMapper.selectTaskNoBySfc(site, sfc);
                if (taskList != null && taskList.size() > 0) {
                    sfcExMapper.closeTask(site, taskList.get(0).getTaskNo());
                }
                UpdateSfcStatusRequest updateSfcStatusRequest = new UpdateSfcStatusRequest();
                updateSfcStatusRequest.setSfcRef(sfcBo);
                // 405->DONE
                updateSfcStatusRequest.setStatusRef(StringUtils.genHandle(HandleBOConstants.STATUS_BO, site, "405"));
                // SfcStateServiceInterface sfcStateServiceInterface = Services.getService("com.sap.me.production", "SfcStateService", site);
                sfcStateServiceInterface.updateSfcStatus(updateSfcStatusRequest);
            }
        } catch (com.sap.me.frame.domain.BusinessException e) {
            throw BusinessException.build(Exceptions.convert(e).toString());
        }
    }

    @Override
    public List<SfcQueuedDto> listReleasableSfc(String site, String resrce) {
        return sfcExMapper.selectReleasableSfc(site, resrce);
    }

    @Override
    public List<SfcQueuedDto> listQueuedOrReleasableSfc(String site, String resrce, String operation) {
        return sfcExMapper.selectQueuedOrReleasableSfc(site, resrce, operation);
    }

    @Override
    public List<SfcInWorkDto> listSfcInWork(String site, String resrce, String operation, String sfc) {
        Locale locale = LocaleContextHolder.getLocale();
        return sfcExMapper.selectSfcInWork(site, locale.getLanguage(), resrce, operation, sfc);
    }

    String generateFinishOperationNumber(String site, ReleaseAndStartSfcDto releaseAndStartSfcDto) {
        String resrce = StringUtils.trimHandle(releaseAndStartSfcDto.getResourceBo());
        CustomFields customFields = customFieldsService.getAttributeValue(releaseAndStartSfcDto.getResourceBo(), CustomFieldsConstant.KW_RESOURCE_SHORT_CODE);
        if (customFields == null) {
            throw BusinessException.build("【" + resrce + "】资源简码未设置");
        }
        Map<String, Object> shiftMap = workCenterShiftService.getCurrentShiftOfResource(site, StringUtils.trimHandle(releaseAndStartSfcDto.getResourceBo()), new Date());
        if (shiftMap == null) {
            throw BusinessException.build("资源【" + resrce + "】未维护班次");
        }
        ShopOrder shopOrder = shopOrderService.selectById(releaseAndStartSfcDto.getShopOrderBo());
        // 使用成品入库编号规则
        NumberingServiceInterface numberingServiceInterface = Services.getService("com.sap.me.numbering", "NumberingService", site);
        GenerateNextNumberRequest generateNextNumberRequest = new GenerateNextNumberRequest();
        generateNextNumberRequest.setNextNumberType(NextNumberTypeEnum.SOBATCHNUMBER);
        generateNextNumberRequest.setNumberOfValues(BigDecimal.ONE);
        generateNextNumberRequest.setItemRef(shopOrder.getPlannedItemBo());
        NameValueObject nameValueObject = new NameValueObject();
        nameValueObject.setName("RESRCE_CODE");
        nameValueObject.setValue(customFields.getValue());
        NameValueObject nameValueObject1 = new NameValueObject();
        nameValueObject1.setName("SHIFT");
        nameValueObject1.setValue(shiftMap.get("shift"));
        List<NameValueObject> nameValueObjectArrayList = new ArrayList<>();
        nameValueObjectArrayList.add(nameValueObject);
        nameValueObjectArrayList.add(nameValueObject1);
        generateNextNumberRequest.setCustomFields(nameValueObjectArrayList);
        GenerateNextNumberResponse generateNextNumberResponse = null;
        try {
            generateNextNumberResponse = numberingServiceInterface.generateNextNumber(generateNextNumberRequest);
        } catch (com.sap.me.frame.domain.BusinessException e) {
            BusinessException.build(Exceptions.convert(e).toString());
        }
        return generateNextNumberResponse.getId().get(0);
    }
}